/**
 * 
 */
package edu.umd.clip.lm.model.training;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class TaskSequencer {
	private boolean reading;
	private final Lock lock;
	private final Condition finishedSomething;
	private int runningTasks;
	private final int maxRunningTasks;
	
	
	/**
	 * @param maxRunningTasks
	 */
	public TaskSequencer(int maxRunningTasks) {
		this.maxRunningTasks = maxRunningTasks;
		this.lock = new ReentrantLock();
		this.finishedSomething = lock.newCondition();
	}

	public void grabInput() {
		try {
			lock.lock();
			while(reading || getRunningTasks() >= maxRunningTasks) {
				try {
					finishedSomething.await();
				} catch (InterruptedException e) {}
			}
			//System.err.println(Thread.currentThread().getName() + " grabbed input");
			reading = true;
			++runningTasks;
		} finally {
			lock.unlock();
		}
	}
	
	public void releaseInput() {
		try {
			lock.lock();
			//System.err.println(Thread.currentThread().getName() + " released input");
			finishedSomething.signalAll();
			reading = false;
		} finally {
			lock.unlock();
		}
	}
	
	public void finish() {
		try {
			lock.lock();
			//System.err.println(Thread.currentThread().getName() + " finished");
			--runningTasks;
			finishedSomething.signalAll();
		} finally {
			lock.unlock();
		}
	}
	
	public boolean waitForSomething(int minTasks) {
		boolean result = false;
		try {
			lock.lock();
			if(getRunningTasks() > minTasks) {
				result = true;
				try {
					finishedSomething.await();
				} catch (InterruptedException e) {}
			}
		} finally {
			lock.unlock();
		}
		return result;
	}
	
	public void join() {
		try {
			lock.lock();
			while(reading || getRunningTasks() > 0) {
				try {
					if (!finishedSomething.await(10, TimeUnit.MINUTES)) {
						System.err.printf("TaskSequencer: waited for %d %s... reading=%s, runningTasks=%d\n", 
								10, TimeUnit.MINUTES, Boolean.toString(reading), runningTasks);
					}
				} catch (InterruptedException e) {}
			}
		} finally {
			lock.unlock();
		}
	}

	public int getRunningTasks() {
		return runningTasks;
	}

	public int getMaxRunningTasks() {
		return maxRunningTasks;
	}
	
}